package Review;
/*HashMap和HashSet底层是一个哈希表，TreeSet和TreeMap底层就是一个红黑树（特殊的二叉搜索树）
* 二分查找的时间复杂度：logN，二分查找一次可以去除一般的数据*/
/*递归的时间复杂度：递归的次数 * 每次递归后代码执行的次数*/
/*递归的空间复杂度：在递归左边的时候右边已经计算完了，此时计算的递归次数就只有一边，有左边就没有右边*/
/*基本数据类型所对应的包装类是引用类型，包装类存在的意义就是可以让基本数据类型面向对象给编程*/
/*平均时间复杂度：如：在数组中找到某一个数据，平均就是  每个数据要找的次数 / 数组的长度，但是一般分析的
* 是最坏时间复杂度*/

import java.util.ArrayList;
import java.util.List;

class MyArray<T> {
    public Object[] obj = new Object[3];

    public Object getPos(int pos) {
        return (T)obj[pos];
    }
    public void setObj(int pos,T val) {
        obj[pos] = val;
    }
}
//把一个类写成泛型类，是需要给这个E一个边界的，否则是不能进行比较的
//否则在运行时期会被擦成Object类型
//写成泛型类之后就可以传过来各种类型的参数
class Alg<E extends Comparable<E>> {
    public E findMax(E[] array) {
        E max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}
class A<E extends Number> {

}
//泛型方法
class Alg2 {//类是一个普通的类，但是里边的方法是泛型的
    //在public后面指定E是什么类型
    public <E extends Comparable<E>> E findMax(E[] array) {
        E max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}
class Alg3 {
    public static <E extends Comparable<E>> E findMax(E[] array) {
        E max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}
public class SetFrameworkPractice {
    public static void main(String[] args) {
        //List本身是一个泛型接口，接口是不能直接实例化的
        //只能是实例化实现该接口的类
        List<Integer> list = new ArrayList<>();
        list.add(1);//这些方法都是接口的方法
        System.out.println(list);
    }

    public static void main9(String[] args) {
        //也可以不实例化对象，把泛型方法写成静态的
        Integer[] array = {1,3,4,5,6,22};
        Integer val = Alg3.findMax(array);
        System.out.println(val);
    }
    public static void main8(String[] args) {
        Alg2 alg2 = new Alg2();
        Integer[] array = {1,2,4,5,8,8,99};
        Integer val = alg2.<Integer>findMax(array);
        //是在引用名之后指定E的类型，但是可以根据array中的数据类型来
        //推导E具体的类型，所以这个是可以省略的
        System.out.println(val);
    }
    public static void main7(String[] args) {
        A<Number> a1 = new A<>();
        A<Integer> a2 = new A<>();
        A<Double> a3 = new A<>();
        //A<String> a4 = new A<String>();
        //如果<E extends Number>的写法，此时E的类型必须是Number本身
        //或者是Number的子类
    }
    public static void main6(String[] args) {
        Alg<Integer> alg = new Alg<>();
        Integer[] array = {1,24,6,7,4,3,11};
        Integer val = alg.findMax(array);
        System.out.println(val);
    }
    public static void main5(String[] args) {
        //实例化对象的同时指定当前泛型类 的指定参数类型是Integer
        //此时编译器就会帮我们检查，如果对应的类型不匹配，编译报错
        //所以泛型是在编译时期的一种机制（就是把一个类型作为参数传递，所以这个参数可以有多个）
        MyArray<Integer> array = new MyArray<>();
        array.setObj(0,12);
        array.setObj(1,22);
        array.setObj(2,33);
        //泛型：1.存储数据：可以帮助我们进行自动类型检查
        //     2.获取元素：可以帮我们进行自动的类型转换
    }
    public static void main4(String[] args) {
        MyArray array = new MyArray();
        array.setObj(0,10);
        array.setObj(1,"hello");
        array.setObj(2,10.0);
        double d = (double) array.getPos(2);
        //此时是可以什么类型都可以存储的，但是获取数据的时候需要进行强转
        //此时的强转：Object是所有类的父类，所以涉及到向下转型和自动拆包
        Object d2 = array.getPos(1);
        //此时虽然编译器不报错了，但是拿到的这个数据进行运算的时候编译器是不知道它的具体的类型的
        //所以说可以在一个容器中放一个指定好的类型，此时就不需要进行强转，同时也知道这个数据
        //的具体类型了
    }
    public static void main3(String[] args) {
        Integer a = 100;
        Integer b = 100;
        System.out.println(a == b);//true

        Integer c = 200;
        Integer d = 200;
        System.out.println(c ==d);//false
        /*自动装箱的时候底层调用的是Integer.valueOf()方法，这个方法中有一个缓存数组，
        * 存放的是-128~127，如果存放的值在这个范围内，此时就去取缓存数组中的值，如果存放
        * 的值超过了这个范围，此时会new一个新的对象*/
    }
    public static void main2(String[] args) {
        //自动拆箱
        Integer val1 = 10;
        int a = val1;//基本数据类型转换成了包装类型
        System.out.println(a);

        //显示拆箱
        int b = val1.intValue();
        System.out.println(b);
        //拆箱不只是可以拆成对象的基本数据类型
        double d = val1.doubleValue();
    }
    public static void main1(String[] args) {
        //自动装箱/装包
        int a = 10;
        //Integer val = a;
        //显示装箱，底层调用的是Integer.valueOf()方法
        Integer val = Integer.valueOf(a);
        Integer val2 = new Integer(a);
        System.out.println(a);

    }
}
